Pinvon's Blog

所见, 所闻, 所思, 所想

精通比特币读书笔记--1

钱包

广义上, 钱包是一个应用程序, 为用户提供交互界面, 钱包控制用户访问权限, 管理密钥和地址, 跟踪余额以及创建和签名交易.

狭义上, 钱包是指存储和管理用户密钥的数据结构.

钱包技术概述

有一种常见的误解是, 比特币钱包里含有比特币. 事实上, 钱包里只含有钥匙, 比特币是被记录在区块链中的. 用户通过钱包中的密钥签名交易, 从而对区块链中的比特币进行控制.

用户用密钥签名交易, 从而证明他们拥有交易输出(比特币), 比特币以交易输出的形式存储在区块链中(通常记为 vout 或 txout).

钱包分成确定性钱包(deterministic wallet)和非确定性钱包(nondeterministic wallet). 其中, 非确定性钱包中的密钥从随机数独立生成, 彼此之间无关. 确定性钱包中的密钥从一个主密钥派生出来, 彼此相关关联.

非确定性钱包

所有密钥彼此独立, 不便管理, 不推荐使用.

确定性钱包

种子足够恢复所有已经产生的私钥, 所以只要备份种子即可. 这样用户可以轻松地在钱包之间转移私钥.

HD 钱包包含以树状结构衍生的密钥, 父密钥可以衍生一系列子密钥, 每个子密钥又可以衍生出一系列孙密钥, 以此类推, 无限衍生. 这种钱包可以应用于企业环境中, 如, 一个特定分支的子密钥用于某部门.

种子和助记词

由一系列英文单词生成种子, 这样易于在钱包中转移, 导入, 导出. 这些英文单词就称为助记词.

助记词的选择是有讲究的, 其生成的步骤如下:

  • 创建一个 128 或 256 位的随机序列(熵)
  • 提取 SHA256 哈希前几位(熵长/32), 得到校验和
  • 将校验和添加到随机序列末尾
  • 将序列以 11bit 的长度进行划分
  • 预先定义 2048 个单词, 根据子序列找出对应的单词
  • 生成的有顺序的单词就是助记词

如图所示:

76.png

交易

概述

比特币交易是比特币系统中最重要的部分. 比特币交易的本质是数据结构, 这些数据结构中含有比特币交易参与者价值转移的相关信息. 比特币区块链是个总账本, 每个比特币交易都是在比特币区块链上的一个公开记录.

交易细节

交易中存储的数据是非常简单的, 区块浏览器中所看到的信息, 很多都是由区块浏览器所构建的, 并非从交易读取.

解码后的交易

Alice-->Bob 的交易, 解码后如下所示:

77.png

仔细查看图中内容, 会发现, 没有 Alice 的地址, 没有 Bob 的地址, 没有 Alice 转出的 0.1BTC. 那么, 没有这些信息, 是如何通过交易链, 找出比特币的最终源头的呢?

交易的输入输出

UTXO

unspent transaction outputs(UTXO): 未消费的交易输出.

UTXO 是比特币交易中的基础构建单元, 不可分割, 记录在区块上.

比特币网络中, 所有的 UTXO 的集合, 称为 UTXO集, 当新的 UTXO 被创建, UTXO集 就会变大, 当 UTXO 被消耗时, UTXO集 就会缩小. 每个交易都代表着 UTXO集 的变化(状态转换).

当钱包显示收到比特币时, 实际上的意思是指钱包检测其控制的密钥可用的 UTXO. 通过钱包控制的密钥, 可以将这些 UTXO 花费出去. 钱包中显示的比特币总和, 是指 UTXO 的总和, 这些 UTXO 可能分散在许多区块中, 钱包会扫描区块链, 把属于该用户的 UTXO 都聚集起来. 钱包会维护一个数据库, 存储该用户的所有 UTXO集.

一个 UTXO 是 1聪 的整数倍, 一旦一个 UTXO 被创建, 就意味着它是不可分割的, 只能作为一个整体被消耗. 即使一个 UTXO 大于一笔所需的花费, 它仍然会当成一个整体被消耗, 同时会产生两个输出: 花费和找零. 但这些细节都由钱包处理, 用户感觉不到.

一笔交易会消耗已存在的 UTXO, 并创建新的 UTXO 来作为未来的交易消耗. 所以, 一笔比特币, 通过在交易链中创建和消耗 UTXO, 在不同的所有者之间转移. 一笔比特币的交易, 通过使用所有者的签名(私钥签名)来解锁 UTXO, 使用接收者的比特币地址(公钥)来锁定并创建 UTXO.

除了交易的输入输出之外, 挖矿时会产生新的比特币, 这也是 UTXO, 会作为区块的第一笔交易写入区块链.

交易输出

几乎每一笔交易, 都会产生 UTXO. UTXO 在 UTXO集 中被每一个全节点比特币客户端追踪. 交易输出包括两个部分:

  • 一定量的比特币(以聪为单位)
  • 确定花费输出所需条件的加密难题(也称为locking script 或 witness script 或 scriptPubKey)

在上面解码交易的图片中, 仔细查看 vout 数组中的内容, 可以看到交易包含两个输出, 每个输出都包括一个值和一个加密难题.

注意, locking script 中的内容包括 接收者的公钥哈希, 意思是, 有谁能提供一个签名和一个公钥, 让这个脚本运行通过, 谁就能花这笔交易的资金. 由于创建签名只能使用接收者的私钥, 其他人的私钥创建的签名无法通过这个脚本的验证, 所以其他人无法假冒接收者来花费这笔输出.

交易序列化--输出

序列化: 将内部的数据结构转换为字节流的过程. 当交易通过网络传输或在应用程序之间进行交换时, 交易会被序列化.

交易输入

交易输入将 UTXO 标记为被消费, 并通过解锁脚本(unlock script)提供所有权证明(即将之前加密难题解锁).

如果要构建交易, 就创建一个或若干个指向 UTXO 的输入, 然后用解锁脚本解锁它(们). 一般情况下, 解锁脚本就是一个证明比特币所有权的数字签名和公钥.

输入包含四个元素:

  • 交易 ID, 引用正在使用的 UTXO 的交易(交易链中关于这个 UTXO 的上一个 ID).
  • 输出索引, 用于标识来自该交易的哪个 UTXO 被引用.
  • 解锁脚本
  • 序列号

交易费

目前的设置是: 1kB 收取 0.00001BTC. 如果一笔交易, 只有一个输入, 一个输出, 那么这笔交易所占的字节数就比较少, 交易费会比较低; 如果有几百个小额输入, 一个大额输出, 这笔交易所占的字节数就多, 交易费也会比较高. 所以, 交易费与交易额的大小无关, 与交易占的字节数有关.

交易的数据结构中没有交易费, 它通过输入输出的差值来计算.

也许钱包会自动帮我们构造交易费的大小, 但是如果我们选择手动构造, 一定要记得填写找零的输出, 否则剩下的钱就都会被当做交易费被矿工收取.

交易脚本

当一笔比特币交易被验证时, 每一个输入值中的解锁脚本和锁定脚本并行执行, 以确定这笔交易是否满足支付条件.

比特币脚本语言没有循环和条件中转, 所以它是图灵非完备语言. 因此, 比特币只能编写简单的智能合约, 能做的事情有限. 比特币脚本被设计成图灵非完备语言, 是有它的原因的, 如果不怀好意的人, 在脚本中写了个无限循环, 会导致资源被严重浪费(类似拒绝服务攻击).

脚本构建

锁定脚本包含公钥或比特币地址(公钥的哈希值), 解锁脚本包含一个由用户的比特币钱包(通过用户的私钥)生成的数字签名(一般情况下, 但不是所有解锁脚本都这样).

输入 = 解锁脚本 + UTXO.

UTXO = 锁定脚本 + ...

这样, 就可以通过输入, 得到解锁脚本和锁定脚本, 然后分别单独执行. 如果解锁脚本满足锁定脚本条件, 则输入有效.

一个简单的例子

任何解锁和锁定脚本的组合如果结果为 TRUE, 则为有效.

假设锁定脚本为: 3 OP_ADD 5 OP_EQUAL

意思是, 哪个数和 3 相加, 如果与 5 相等, 就验证通过.

然后, 解锁脚本的内容为: 2

验证软件将锁定脚本和解锁脚本的内容组合起来, 就是: 2 3 OP_ADD 5 OP_EQUAL

于是, 验证通过.

在实际中, 锁定脚本包含一个公钥哈希值; 解锁脚本包含接收者的公钥和由相应私钥创建的数字签名. 将这两个结合起来, 即可通过验证.

以 Alice --> Bob 为例.

该交易的 UTXO 中, 包含 Bob 的公钥哈希(即下面的 Cafe Public Key Hash):

OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

解锁脚本是:

<Cafe Signature> <Cafe Public Key>

将两个脚本组合:

<Cafe Signature> <Cafe Public Key> OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

可以理解为: 当解锁脚本得到了接收者的有效签名, 验证就会通过. 这个有效签名是从与公钥哈希对应的私钥获取.

Comments

使用 Disqus 评论
comments powered by Disqus